package mornd.custom;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.web.servlet.HandlerExecutionChain;
import org.springframework.web.servlet.HandlerMapping;
import org.springframework.web.servlet.mvc.Controller;

import javax.servlet.http.HttpServletRequest;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author: mornd
 * @dateTime: 2023/5/9 - 17:04
 * 自定义 HandlerMapping （找到请求路径映射关系）
 */
public class MyHandlerMapping
        implements HandlerMapping, InitializingBean, ApplicationContextAware {

    private ApplicationContext applicationContext;
    private Map<String, Controller> handlerMap = new HashMap<>();

    @Override
    public boolean usesPathPatterns() {
        return HandlerMapping.super.usesPathPatterns();
    }

    /**
     * 请求来的时候，执行此方法
     * @param request current HTTP request
     * @return
     * @throws Exception
     */
    @Override
    public HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
        // /c3
        String requestURI = request.getRequestURI();

        Controller controller = handlerMap.get(requestURI);

        if(controller == null) {
            // dispatcherServlet 执行时 noHandlerFound(processedRequest, response);
            // 发现值为 null，返回 status 404
            return null;
        }
        return new HandlerExecutionChain(controller);
    }

    /**
     * 初始化，找到容器中的路径映射关系
     * @throws Exception
     */
    @Override
    public void afterPropertiesSet() throws Exception {
        Map<String, Controller> beanList = applicationContext.getBeansOfType(Controller.class);
        handlerMap = beanList.entrySet().stream()
                .filter(e -> e.getKey().startsWith("/"))
                .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
//        beanList.forEach((k,v) -> {
//            if(k.startsWith("/")) {
//                handlerMap.put(k, v);
//            }
//        });
        System.out.println(handlerMap);
    }

    public Map<String, Controller> getHandlerMap() {
        return Collections.unmodifiableMap(handlerMap);
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }
}
